/**
 * 
 */
package com.worksmap.core.listener;

import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.taobao.api.internal.tmc.Message;
import com.taobao.api.internal.tmc.MessageHandler;
import com.taobao.api.internal.tmc.MessageStatus;
import com.taobao.api.internal.tmc.TmcClient;
import com.taobao.top.link.LinkException;
import com.worksmap.core.constant.RateConstant;
import com.worksmap.core.entity.TaoBaoOrder;
import com.worksmap.core.entity.Trade;
import com.worksmap.core.exception.WebUtilException;
import com.worksmap.core.service.TradeService;

/**
 * 启动web时掉起tb的消息服务，项目启动时，启动该listener
 * @author jack
 *
 */
public class TmcClientListener extends TmcClientHelper implements ServletContextListener , HttpSessionListener{
	
	Logger logger = Logger.getLogger(this.getClass());
	
	private static TradeService tradeService = null;
	
	/**
	 * 此方法仅在关闭Web容器(或服务器)时被调用一次  
	 * 关闭tb的消息服务
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		event.getServletContext().log("关闭tb的消息服务,任务执行结束");
		logger.info("关闭tb的消息服务,任务执行结束");
	}

	/**
	 * 此方法仅在起动Web容器(或服务器)时被调用一次   
	 * 启动tb的消息服务
	 * 淘宝会对每个message新建一个线程（线程池）
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		logger.info("开启tb的消息服务,任务执行开始，直到web服务关闭");
		javax.servlet.ServletContext ctx = event.getServletContext();  
        ctx.log("--------任务开始执行");  
//        TmcClient client = new TmcClient(RateConstant.appkey, RateConstant.appSecret);     //真实环境
		TmcClient client = new TmcClient("ws://mc.api.tbsandbox.com/", 
				RateConstant.appkey, RateConstant.appSecret, "default");         		   //沙箱
        client.setMessageHandler(new MessageHandler() {  
			/** 
		     * 消息服务客户端收到消息后，会回调该方法处理具体的业务，处理结果可以通过以下两种方式来表述： 
		     * <li>抛出异常或设置status.fail()表明消息处理失败，需要消息服务端重发 
		     * <li>不抛出异常，也没有设置status信息，则表明消息处理成功，消息服务端不会再投递此消息 
		     * @param message 消息内容 
		     * @param status 处理结果，如果调用status.fail()，消息服务将会择机重发消息；否则，消息服务认为消息处理成功 
		     * @throws Exception 消息处理失败，消息服务将会择机重发消息 
		     */  
			@Override
		    public void onMessage(Message message, MessageStatus status) {  
		        try {  
		        	if(!RateConstant.TMC_MESSAGE.containsKey(message.getTopic())){
		        		return;
		        	}
		        	int topicId = RateConstant.TMC_MESSAGE.get(message.getTopic());
		        	switch (topicId){
		        	 case 1:	//交易评价变更消息
		        		 handleTradeRated(message);
		        		 break;
		             case 2:    //交易成功消息
		            	 handleTradeSuccess(message);
		            	 break;
		        	}
		            // 默认不抛出异常则认为消息处理成功  
		        } catch (Exception e) {  
		        	logger.error("消息服务，接受消息处理失败:" + e);
		            e.printStackTrace();  
		            status.fail();// 消息处理失败回滚，服务端需要重发  
		        }  
		    }
		});  
		try {
			client.connect();
		} catch (LinkException e) {
			e.printStackTrace();
		}
	}
	
	private void handleTradeRated(Message message){
		logger.info("交易评价变更消息:" + message.getContent());
		Trade trade = getRatedTradeByMessage(message);
		//根据tid查询订单详情，订单评价情况
		List<TaoBaoOrder> orderList = tradeService.getOrderListByTid(trade);
		if(orderList == null || orderList.size() <= 0){
			throw new WebUtilException("交易评价变更消息，获取订单详情失败!");
		}
		boolean buyerRateStatus = true;
		for(TaoBaoOrder order: orderList){
			if(!order.getBuyer_rate()){
				buyerRateStatus = false;
			}
			if(order.getSeller_rate()){
				return;
			}
		}
		if(buyerRateStatus){   //更新本地订单trade表的rate_status_buyer为1，即买家已评价该订单
			trade.setRate_status_buyer(1);
			if(!tradeService.updateTrade(trade, new String[]{"rate_status_buyer"})){
				throw new WebUtilException("更新本地订单trade表的rate_status_buyer为1失败！");
			}
		}
	}
	
	private void handleTradeSuccess(Message message){
		logger.info("交易成功消息:" + message.getContent());
		Trade trade = getTradeByMessage(message);
		if(!tradeService.saveTrade(trade)){
			throw new WebUtilException("保存交易成功订单失败！");
		}
	}

	@Override
	public void sessionCreated(HttpSessionEvent event) {
		HttpSession session=event.getSession();
		//通过抽象的私有方法得到Spring容器中Bean的实例。
		tradeService = (TradeService)this.getObjectFromApplication(session.getServletContext(), "tradeService");
		logger.info("取得的tradeService的实例=" + tradeService);
	}
	
	private Object getObjectFromApplication(ServletContext servletContext,String beanName){
		//通过WebApplicationContextUtils 得到Spring容器的实例。
		ApplicationContext application=WebApplicationContextUtils.getWebApplicationContext(servletContext);
		//返回Bean的实例。
		return application.getBean(beanName);
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent arg0) {
		
	}
}
